package edu.friday.service.impl;

import edu.friday.common.constant.UserConstants;
import edu.friday.common.result.TreeSelect;
import edu.friday.model.SysMenu;
import edu.friday.model.vo.MetaVo;
import edu.friday.model.vo.RouterVo;
import edu.friday.model.vo.SysMenuVO;
import edu.friday.model.vo.SysUserVO;
import edu.friday.repository.ISysMenuRepository;
import edu.friday.service.ISysMenuService;
import edu.friday.utils.BeanUtils;
import edu.friday.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.ExampleMatcher;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

@Service
@Transactional
public class SysMenuServiceImpl implements ISysMenuService {

    @Autowired
    private ISysMenuRepository iSysMenuRepository;

    @Override
    public Set<String> selectMenuPermissionByUserId(Long userId) {
        Set<String> perms = iSysMenuRepository.selectPermsByUserId(userId);
        perms.removeIf(String::isEmpty);
        return perms;
    }

    @Override
    public List<SysMenu> selectMenuList(SysMenuVO sysMenuVO, Long userId) {
        List<SysMenu> list = null;
        SysMenu sysMenu = new SysMenu();
        BeanUtils.copyPropertiesIgnoreEmpty(sysMenuVO, sysMenu);
        Sort sort = Sort.by("parentId", "orderNum");
        ExampleMatcher exampleMatcher = ExampleMatcher.matching()
                .withMatcher("menuName", ExampleMatcher.GenericPropertyMatchers.contains());
        if (SysUserVO.isAdmin(userId))
            list = iSysMenuRepository.findAll(Example.of(sysMenu, exampleMatcher), sort);
        else list = iSysMenuRepository.selectMenuListByUserId(sysMenu, userId);
        return list;
    }

    @Override
    public List<SysMenu> selectMenuList(Long userId) {
        return selectMenuList(new SysMenuVO(), userId);
    }

    @Override
    public SysMenu selectMenuById(Long menuId) {
        Optional<SysMenu> op = iSysMenuRepository.findById(menuId);
        return op.orElse(null);
    }

    @Override
    public boolean insertMenu(SysMenuVO sysMenuVO) {
        SysMenu sysMenu = new SysMenu();
        BeanUtils.copyPropertiesIgnoreEmpty(sysMenuVO, sysMenu);
        iSysMenuRepository.save(sysMenu);
        return StringUtils.isNotNull(sysMenu.getMenuId());
    }

    @Override
    public String checkMenuNameUnique(SysMenuVO sysMenuVO) {
        Long menuId = StringUtils.isNull(sysMenuVO.getMenuId()) ? -1L : sysMenuVO.getMenuId();
        SysMenu sysMenu = new SysMenu();
        sysMenu.setMenuName(sysMenuVO.getMenuName());
        //sysMenu.setParentId();
        Optional<SysMenu> one = iSysMenuRepository.findOne(Example.of(sysMenu));
        if (one.isPresent() && one.get().getMenuId().longValue() != menuId.longValue())
            return UserConstants.NOT_UNIQUE;
        else return UserConstants.UNIQUE;
    }

    @Override
    public boolean updateMenu(SysMenuVO sysMenuVO) {
        Long menuId = sysMenuVO.getMenuId();
        Optional<SysMenu> op = iSysMenuRepository.findById(menuId);
        if (!op.isPresent())
            return false;
        SysMenu sysMenu = op.get();
        BeanUtils.copyPropertiesIgnoreEmpty(sysMenuVO, sysMenu);
        iSysMenuRepository.save(sysMenu);
        return true;
    }

    @Override
    public boolean deleteMenuById(Long menuId) {
        iSysMenuRepository.deleteById(menuId);
        return true;
    }

    @Override
    public boolean hasChildByMenuId(Long menuId) {
        SysMenu sysMenu = new SysMenu();
        sysMenu.setParentId(menuId);
        long count = iSysMenuRepository.count(Example.of(sysMenu));
        return count>0;
    }

    @Override
    public boolean checkMenuExistRole(Long menuId) {
        return iSysMenuRepository.checkMenuExistRole(menuId) > 0;
    }

    @Override
    public List<TreeSelect> buildMenuTreeSelect(List<SysMenuVO> sysMenuVOS) {
        List<SysMenuVO> menuTrees = buildMenuTree(sysMenuVOS);
        //将menuTrees列表中的每个SysMenuVO对象转换成TreeSelect对象
        return menuTrees.stream().map(TreeSelect::new).collect(Collectors.toList());
    }

    @Override
    public List<Long> selectMenuListByRoleId(Long roleId) {
        List<SysMenu> sysMenus = iSysMenuRepository.selectMenuListByRoleId(roleId);
        List<Long> result = new ArrayList<>();
        for (SysMenu sysMenu : sysMenus)
            result.add(sysMenu.getMenuId());
        return result;
    }

    @Override
    public List<SysMenuVO> selectMenuTreeByUserId(Long userId) {
        List<SysMenu> menus = iSysMenuRepository.selectMenuTreeByUserId(userId);
        List<SysMenuVO> menuVOS = BeanUtils.copyProperties(menus, SysMenuVO.class);
        return getChildPerms(menuVOS, 0);
    }

    @Override
    public List<SysMenuVO> getChildPerms(List<SysMenuVO> menuVOS, int parentId) {
        List<SysMenuVO> returnList = new ArrayList<SysMenuVO>();
        for (SysMenuVO menuVO : menuVOS) {
            if (menuVO.getParentId() == parentId) {
                recursionFn(menuVOS, menuVO);
                returnList.add(menuVO);
            }
        }
        return returnList;
    }

    @Override
    public List<RouterVo> buildMenus(List<SysMenuVO> menus) {
        List<RouterVo> routers = new LinkedList<RouterVo>();
        for (SysMenuVO menu : menus) {
            RouterVo router = new RouterVo();
            router.setName(StringUtils.capitalize(menu.getPath()));
            router.setPath(getRouterPath(menu));
            router.setComponent(StringUtils.isEmpty(menu.getComponent()) ? "Layout" : menu.getComponent());
            router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon()));
            List<SysMenuVO> cMenus = menu.getChildren();
            if (!cMenus.isEmpty() && "M".equals(menu.getMenuType())) {
                router.setAlwaysShow(true);
                router.setRedirect("noRedirect");
                router.setChildren(buildMenus(cMenus));
            }
            routers.add(router);
        }
        return routers;
    }

    private String getRouterPath(SysMenuVO menu) {
        if (0 == menu.getParentId() && 1 == menu.getIsFrame())
            return "/" + menu.getPath();
        return menu.getPath();
    }

    private List<SysMenuVO> buildMenuTree(List<SysMenuVO> sysMenuVOS) {
        List<SysMenuVO> result = new ArrayList<>();
        for (SysMenuVO sysMenuVO : sysMenuVOS) {
            if (sysMenuVO.getParentId() == 0) {
                //递归获取子节点
                recursionFn(sysMenuVOS, sysMenuVO);
                result.add(sysMenuVO);
            }
        }
        return result;
    }

    private void recursionFn(List<SysMenuVO> list, SysMenuVO p) {
        //1.获取p的所有子节点
        List<SysMenuVO> childList = getChildList(list, p);
        p.setChildren(childList);
        //如果为空,说明没有子节点
        if (StringUtils.isEmpty(childList))
            return;
        for (SysMenuVO sysMenuVO : childList) {
            recursionFn(list, sysMenuVO);
        }
    }

    private List<SysMenuVO> getChildList(List<SysMenuVO> list, SysMenuVO p) {
        List<SysMenuVO> result = new ArrayList<>();
        for (SysMenuVO sysMenuVO : list) {
            if (sysMenuVO.getParentId().longValue() == p.getMenuId().longValue())
                result.add(sysMenuVO);
        }
        return result;
    }
}
